package com.tbit.uqbike.object.business;

import com.tbit.uqbike.constant.MapConstant;
import com.tbit.uqbike.service.base.CalibrateService;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.List;
import java.util.Objects;

/**
 * @author MyWin E-mail:335918956@qq.com
 * @version 1.0
 * @createTime 2019-12-10 15:26
 */
@Slf4j
public class CalibrateUtils {

    public static final String DEF_LON = "lon";
    public static final String DEF_LAT = "lat";
    public static final String DEF_LON_C = "lonC";
    public static final String DEF_LAT_C = "latC";
    public static final Integer LEN = 6;

    private static Double formatDouble(Double d) {
        BigDecimal b = new BigDecimal(d);
        return b.setScale(LEN, BigDecimal.ROUND_DOWN).doubleValue();
    }

    public static <T> void calibrateObject(CalibrateService calibrateService, T obj, Integer mapType, String lonName, String loncName, String latName, String latcName) {
        try {
            Double lon = (Double) getFieldValueByFieldName(lonName, obj);
            Double lat = (Double) getFieldValueByFieldName(latName, obj);
            if (lon != null && lat != null) {
                Point point = calibrateService.calibrateOffSet(lon, lat, mapType);
                setFieldValueByFieldName(loncName, obj, formatDouble(point.getX()));
                setFieldValueByFieldName(latcName, obj, formatDouble(point.getY()));
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            System.out.println(e.getMessage());
        }
    }

    public static <T> void calibrateObjects(CalibrateService calibrateService, List<T> objs, Integer mapType, String lonName, String loncName, String latName, String latcName) {
        if (mapType == null) {
            mapType = MapConstant.MAP_GOOGLE;
        }

        for (T obj : objs) {
            calibrateObject(calibrateService, obj, mapType, lonName, loncName, latName, latcName);
        }
    }

    public static <T> void calibrateObject(CalibrateService calibrateService, T obj, Integer mapType) {
        calibrateObject(calibrateService, obj, mapType, DEF_LON, DEF_LON_C, DEF_LAT, DEF_LAT_C);
    }

    public static <T> void calibrateObjects(CalibrateService calibrateService, List<T> objs, Integer mapType) {
        calibrateObjects(calibrateService, objs, mapType, DEF_LON, DEF_LON_C, DEF_LAT, DEF_LAT_C);
    }

    /**
     * 根据属性名获取属性值
     *
     * @param fieldName
     * @param object
     * @return
     */
    private static Object getFieldValueByFieldName(String fieldName, Object object) throws NoSuchFieldException, IllegalAccessException {
        Class c = object.getClass();
        Field field = getFieldByName(c, fieldName);
        //设置对象的访问权限，保证对private的属性的访问
        field.setAccessible(true);
        return field.get(object);
    }

    private static Field getFieldByName(Class clazz, String fieldName) {
        Field field = null;
        while (clazz != null) {
            Field[] fields = clazz.getDeclaredFields();
            for (Field f : fields) {
                if (Objects.equals(f.getName(), fieldName)) {
                    field = f;
                    break;
                }
            }
            if (null != field) {
                break;
            } else {
                clazz = clazz.getSuperclass();
            }
        }
        return field;
    }

    /**
     * 根据属性名设置属性值
     *
     * @param fieldName
     * @param object
     * @return
     */
    private static void setFieldValueByFieldName(String fieldName, Object object, Object value) throws NoSuchFieldException, IllegalAccessException {
        // 获取obj类的字节文件对象
        Class c = object.getClass();
        // 获取该类的成员变量
        Field f = getFieldByName(c, fieldName);
        // 取消语言访问检查
        f.setAccessible(true);
        // 给变量赋值
        f.set(object, value);
    }
}
